﻿//
// Created by LiuYou on 2021/4/25.
//

//#include <cstdio>
#include <cstring>
#include <unistd.h>
//#include <cstdlib>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cout << "Using:./client ip port" << std::endl
                  << "Example:./client 127.0.0.1 5005" << std::endl;
//        printf("Using:./client ip port\nExample:./client 127.0.0.1 5005\n\n");
        return -1;
    }

    // 第1步：创建客户端的socket。
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket == -1) {
        perror("socket");
        return -1;
    }

    // 第2步：向服务器发起连接请求。
    hostent* ptrHostEntry = gethostbyname(argv[1]);
    // 指定服务端的ip地址。
    if (ptrHostEntry == nullptr) {
        std::cout << "gethostbyname failed." << std::endl;
//        printf("gethostbyname failed.\n");
        close(clientSocket);
        return -1;
    }

/*    sockaddr_in servaddr{};
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    // 指定服务端的通信端口。
    servaddr.sin_port = htons(atoi(argv[2]));*/

    std::string portStr(argv[2]);
    sockaddr_in serverAddress{
            .sin_family=AF_INET,
            .sin_port=htons(std::stoul(portStr))
    };
    memcpy(&serverAddress.sin_addr, ptrHostEntry->h_addr, ptrHostEntry->h_length);
//    memcpy(&servaddr.sin_addr, ptrHostEntry->h_addr, ptrHostEntry->h_length);

    // 向服务端发起连接清求。
    int connectReturnValue = connect(clientSocket, (sockaddr*) &serverAddress, sizeof(serverAddress));
    if (connectReturnValue != 0) {
        perror("connect");
        close(clientSocket);
        return -1;
    }

    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

/*    char buffer[1024];

    // 第3步：与服务端通信，发送一个报文后等待回复，然后再发下一个报文。
    for (int i = 0; i < 3; ++i) {
        memset(buffer, 0, sizeof(buffer));
        // 将格式化输出内容赋值到buffer所指向的字符串, 其实就是buffer字符数组中。
        sprintf(buffer, "这是第%d个超级女生，编号%03d。", i + 1, i + 1);

        // 向服务端发送请求报文。
        ssize_t sendReturnValue = send(clientSocket, buffer, strlen(buffer), 0);
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << *buffer << std::endl;
//        printf("发送：%s\n", buffer);

        memset(buffer, 0, sizeof(buffer));
        ssize_t recvReturnValue = recv(clientSocket, buffer, sizeof(buffer), 0);
        // 接收服务端的回应报文。
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
//            printf("recvReturnValue=%zd\n", recvReturnValue);
            break;
        }
        std::cout << "接受: " << *buffer << std::endl;
//        printf("接收：%s\n", buffer);
    }*/

    char buffer[1024];

    // 第3步：与服务端通信，发送一个报文后等待回复，然后再发下一个报文。
    for (int i = 0; i < 10; ++i) {
        memset(buffer, 0, sizeof(buffer));
        // 将格式化输出内容赋值到buffer所指向的字符串, 其实就是buffer字符数组中。
        sprintf(buffer, "这是第%d个超级女生，编号%03d。", i + 1, i + 1);

        // 向服务端发送请求报文。
        ssize_t sendReturnValue = send(clientSocket, buffer, strlen(buffer), 0);
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << std::string(buffer) << std::endl;
//        std::cout << "发送: " << *buffer << std::endl;

        memset(buffer, 0, sizeof(buffer));
        ssize_t recvReturnValue = recv(clientSocket, buffer, sizeof(buffer), 0);
        // 接收服务端的回应报文。
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
            break;
        }
        std::cout << "接受: " << std::string(buffer) << std::endl;
//        std::cout << "接受: " << *buffer << std::endl;
        sleep(1);
    }

// TODO 注意: 还是使用C的原始数组和原始指针吧！！！！通过资料查阅在C++的boost库中有一个asio库, 这个库封装了原始的socket。所以如果不使用
//  这些库的话那就使用原始的socket(即C式的socket编程吧)。

/*    std::string buffer[1024];
    // 第3步：与服务端通信，发送一个报文后等待回复，然后再发下一个报文。
    for (int i = 0; i < 3; ++i) {
        buffer->clear();
        buffer->append("");
//        buffer = "";
        // 将格式化输出内容赋值到buffer所指向的字符串, 其实就是buffer字符数组中。
        buffer->append("这是第" + std::to_string(i + 1) + "个超级女生，编号" + std::to_string(i + 1) + "。");
//        buffer = "这是第" + std::to_string(i + 1) + "个超级女生，编号" + std::to_string(i + 1) + "。";

        // 向服务端发送请求报文。
        ssize_t sendReturnValue = send(clientSocket, buffer, sizeof(buffer), 0);
//        std::cout << "buffer的长度: " << std::endl
//                  << "buffer.length(): " << buffer.length() << std::endl
//                  << "sizeof(buffer.c_str()): " << sizeof(buffer.c_str()) << std::endl;
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << *buffer << std::endl;

        buffer->clear();
        buffer->append("");
//        buffer = "";
//        ssize_t recvReturnValue = recv(clientSocket, (void*) buffer.c_str(), sizeof(buffer.c_str()), 0);
        ssize_t recvReturnValue = recv(clientSocket, buffer, sizeof(buffer), 0);
//        ssize_t recvReturnValue = recv(clientSocket, const_cast<char*>(buffer.c_str()), std::strlen(buffer.c_str()) + 1,0);
//        ssize_t recvReturnValue = recv(clientSocket, const_cast<char*>(buffer.c_str()), sizeof(buffer.c_str()), 0);
        // 接收服务端的回应报文。
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
            break;
        }
        std::cout << "接受: " << *buffer << std::endl;
    }*/

    // 第4步：关闭socket，释放资源。
    close(clientSocket);
}